package cn.wei.youvierpc.server.tcp;

import cn.wei.youvierpc.model.RpcRequest;
import cn.wei.youvierpc.model.RpcResponse;
import cn.wei.youvierpc.protocol.ProtocolMessage;
import cn.wei.youvierpc.protocol.ProtocolMessageDecoder;
import cn.wei.youvierpc.protocol.ProtocolMessageEncoder;
import cn.wei.youvierpc.protocol.ProtocolMessageTypeEnum;
import cn.wei.youvierpc.registry.LocalRegistry;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TcpServerHandler implements Handler<NetSocket> {
    @Override
    public void handle(NetSocket netSocket) {
        TcpBufferHandlerWrapper  bufferHandlerWrapper = new TcpBufferHandlerWrapper(buffer -> {
            ProtocolMessage<RpcRequest> message;
            try {
                message = (ProtocolMessage<RpcRequest>) ProtocolMessageDecoder.decode(buffer);
            } catch (IOException e) {
                throw new RuntimeException("协议消息解码出错！");
            }
            RpcRequest rpcRequest = message.getBody();

            RpcResponse rpcResponse = new RpcResponse();

            Class<?> aClass = LocalRegistry.get(rpcRequest.getServiceName());
            try {
                Method method = aClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
                Object result = method.invoke(aClass.getDeclaredConstructor().newInstance(), rpcRequest.getArgs());

                rpcResponse.setData(result);
                rpcResponse.setDataType(method.getReturnType());
                rpcResponse.setMessage("OK");
            } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
                     InvocationTargetException e) {
                e.printStackTrace();
                rpcResponse.setException(e);
                rpcResponse.setMessage(e.getMessage());
            }

            ProtocolMessage.Header header = message.getHeader();
            header.setType((byte) ProtocolMessageTypeEnum.RESPONSE.getKey());
            ProtocolMessage<RpcResponse> responseProtocolMessage = new ProtocolMessage<>(header, rpcResponse);

            try {
                Buffer encode = ProtocolMessageEncoder.encode(responseProtocolMessage);
                netSocket.write(encode);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        netSocket.handler(bufferHandlerWrapper);
    }
}
